package epay18

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/go-resty/resty/v2"
	"github.com/jinzhu/copier"
	"github.com/zeromicro/go-zero/core/logx"
	"strconv"
)

const depositApplyURI = "/pay/center/deposit/apply"

type DepositApplyReq struct {
	Amount          string `json:"amount"`
	Channel         string `json:"channel"`
	MerchantTradeNo string `json:"merchantTradeNo"`
	TerminalType    int64  `json:"terminalType"`
	UserId          string `json:"userId"`
}

type DepositApplyResp struct {
	Status          string `json:"status"`
	ErrorCode       string `json:"errorCode"`
	Msg             string `json:"msg"`
	MerchantTradeNo string `json:"merchantTradeNo"`
	PayUrl          string `json:"payUrl"`
	Sign            string `json:"sign"`
	TradeNo         string `json:"tradeNo"`
	TradeStatus     string `json:"tradeStatus"`
}

type DepositApplyReqContent struct {
	Amount          string `json:"amount"`
	Channel         string `json:"channel"`
	MerchantCode    string `json:"merchantCode"`
	MerchantTradeNo string `json:"merchantTradeNo"`
	NotifyUrl       string `json:"notifyUrl"`
	Sign            string `json:"sign"`
	TerminalType    int64  `json:"terminalType"`
	UserId          string `json:"userId"`
}

type DepositApplyRespBody struct {
	Status    string `json:"status"`
	ErrorCode string `json:"errorCode"`
	Msg       string `json:"msg"`
	Data      string `json:"data"` // 响应数据（json字符串）
}

type DepositApplyRespBodyData struct {
	MerchantCode string `json:"merchantCode"`
	SignType     string `json:"signType"`
	Content      string `json:"content"`
}

type DepositApplyRespContent struct {
	MerchantCode    string `json:"merchantCode"`
	MerchantTradeNo string `json:"merchantTradeNo"`
	PayUrl          string `json:"payUrl"`
	Sign            string `json:"sign"`
	TradeNo         string `json:"tradeNo"`
	TradeStatus     string `json:"tradeStatus"`
}

func (r *HttpClient) DepositApply(ctx context.Context, req *DepositApplyReq) (resp *DepositApplyResp, err error) {
	// md5
	var reqBody DepositApplyReqContent
	_ = copier.Copy(&reqBody, req)

	reqBody.MerchantCode = r.MerchantCode
	if r.NotifyUrlPrefix != "" {
		reqBody.NotifyUrl = r.NotifyUrlPrefix + "/deposit"
	}
	sign := Md5v(reqBody.Amount + reqBody.Channel + reqBody.MerchantCode + reqBody.MerchantTradeNo + reqBody.NotifyUrl + strconv.FormatInt(reqBody.TerminalType, 10) + reqBody.UserId + r.MD5Key)
	reqBody.Sign = sign

	var reqBuf []byte
	reqBuf, err = json.Marshal(reqBody)
	if err != nil {
		return
	}

	var respBody DepositApplyRespBody
	var rsp *resty.Response

	rsp, err = r.cli.R().SetHeader("Content-Type", "application/json;charset=UTF-8").
		SetHeader("Accept", "application/json").SetBody(map[string]string{
		"merchantCode": r.MerchantCode,
		"signType":     "md5",
		"content":      string(reqBuf),
	}).SetResult(&respBody).SetError(&respBody).Post(r.Host + depositApplyURI)
	if err != nil {
		return
	}
	if rsp.IsError() {
		err = errors.New(rsp.Status())
		return
	}

	resp = &DepositApplyResp{}
	_ = copier.Copy(resp, &respBody)
	if respBody.Status == "SUCCESS" {
		var respBodyData DepositApplyRespBodyData
		err = json.Unmarshal([]byte(respBody.Data), &respBodyData)
		if err != nil {
			return
		}
		var respContent DepositApplyRespContent
		err = json.Unmarshal([]byte(respBodyData.Content), &respContent)
		if err != nil {
			return
		}
		_ = copier.Copy(resp, &respContent)
	} else {
		logx.WithContext(ctx).Errorf("DepositApply req param:%s, resp:%+v", string(reqBuf), respBody)
	}
	return
}
